﻿
#include <list>
#include <vector>
#include <ctype.h>
#include "Core.h"
#include "Util.h"
#include "AirlineReservationSystem.h"

namespace AirlineRes
{

AirlineReservationSystem::AirlineReservationSystem()
  : c_filePathFlights( "test_fcgdata.txt" ),
    c_filePathBooking( "bookings.txt" ),
    c_filePathCustomer( "customers.txt" ),
    c_filePathUser( "users.txt" ),
    m_userIsAdmin(false)
{
}

void AirlineReservationSystem::Init()
{
  int err = 0;
  err += m_flightRecords.LoadRecords( c_filePathFlights );
  err += m_bookingRecords.LoadRecords( c_filePathBooking );
  err += m_customerRecords.LoadRecords( c_filePathCustomer );
  err += m_userRecords.LoadRecords( c_filePathUser );
  if ( err != 0 )
  {
    std::cout << "FATAL ERROR LOADING DATABASE. EXITING.\n";
    exit(1);
  }
}

void AirlineReservationSystem::Shutdown()
{
  m_flightRecords.WriteRecords( "testoutput_" + c_filePathFlights );
  m_bookingRecords.WriteRecords( "testoutput_" + c_filePathBooking );
  m_customerRecords.WriteRecords( "testoutput_" + c_filePathCustomer );
  m_userRecords.WriteRecords( "testoutput_" + c_filePathUser );
}

void AirlineReservationSystem::Run()
{
Login:
  InterfaceResult result = LoginScreen();
  if ( result == InterfaceResult_Abort ) return;

  InterfaceResult menuRes;
  if ( m_userIsAdmin )
  {
    menuRes = AdminMenu();
  } else {
    menuRes = RegularUserMenu();
  }
  if ( menuRes == InterfaceResult_Logout )
  {
    goto Login;
  }
}

AirlineReservationSystem::InterfaceResult AirlineReservationSystem::LoginScreen()
{
  system("cls");
  std::cout << "                                                              |\n";
  std::cout << "                                                              |\n";
  std::cout << "                                                             _|_\n";
  std::cout << "       _      _ _                                           /___\\\n";
  std::cout << "  __ _(_)_ __| (_)_ __   ___                               /_____\\\n";
  std::cout << " / _` | | '__| | | '_ \\ / _ \\ \\___________________________\\       /___________________________/\n";
  std::cout << "| (_| | | |  | | | | | |  __/   -----------|------|--------\\_____/--------|------|-----------'\n";
  std::cout << " \\__,_|_|_|  |_|_|_| |_|\\___|             ( )    ( )     O|OOo|oOO|O     ( )    ( )\n";
  std::cout << "                                    _   _                              _                 \n";
  std::cout << " _ __ ___  ___  ___ _ ____   ____ _| |_(_) ___  _ __     ___ _   _ ___| |_ ___ _ __ ___  \n";
  std::cout << "| '__/ _ \\/ __|/ _ \\ '__\\ \\ / / _` | __| |/ _ \\| '_ \\   / __| | | / __| __/ _ \\ '_ ` _ \\ \n";
  std::cout << "| | |  __/\\__ \\  __/ |   \\ V / (_| | |_| | (_) | | | |  \\__ \\ |_| \\__ \\ ||  __/ | | | | |\n";
  std::cout << "|_|  \\___||___/\\___|_|    \\_/ \\__,_|\\__|_|\\___/|_| |_|  |___/\\__, |___/\\__\\___|_| |_| |_|\n";
  std::cout << "                                                             |___/                       \n";

  bool success = false;
  bool quit = false;

  std::string username, password;
  
  while ( !(success || quit) )
  {
    std::cout << "Username:\n> ";
    std::cin.sync();
    std::cin >> username;
    std::cout << "Password:\n> ";
    std::cin.sync();
    std::cin >> password;

    success = UserCredentialsValid( username, password );
    if ( !success )
    {
      std::cout << "\nInvalid username or password. Enter 'x' to exit or any other input to retry.\n> ";
      char x;
      std::cin.sync();
      std::cin.get( x );
      std::cin.sync();
      if ( x == 'x' )
      {
        quit = true;
      }
      std::cout << "\n";
    }

  }

  if ( quit )
  {
    return InterfaceResult_Abort;
  } else if ( success ) {
    auto userRS = m_userRecords.GetRecordSet();
    auto user = *std::find_if(
      userRS->begin(), userRS->end(),
      [&](UserRecord const& _a){ return _a.GetUsername() == username; }
    );
    m_userIsAdmin = user.GetIsAdmin();
    return InterfaceResult_Success;
  } else {
    return InterfaceResult_Unknown;
  }
  
}

bool AirlineReservationSystem::UserCredentialsValid
(
  std::string const& _username,
  std::string const& _password
)
{
  auto userRS = m_userRecords.GetRecordSet();

  auto it = std::find_if(
    userRS->begin(), userRS->end(),  
    [&](UserRecord const& _a){ return _a.GetUsername() == _username && _a.GetPassword() == _password; }
  );

  return ( it == userRS->end() ) ? false : true;
}

AirlineReservationSystem::InterfaceResult AirlineReservationSystem::AdminMenu()
{
  enum MenuOption
  {
    MenuOption_Exit,
    MenuOption_Flights,
    MenuOption_Customers,
    MenuOption_Bookings,
    MenuOption_Users
  };

  std::string const adminMenuPrompt = std::string() +
    "=============================================\n" +
	"\n           Administrator User Menu          \n" +
	"\n=============================================\n" +
    "Enter a number corresponding to the record type that you wish to operate upon.\n" +
    "\n" +
    " 1. Flights.         0. Exit.\n" +
    " 2. Customers.\n" +
    " 3. Bookings.\n" +
    " 4. System Users.\n" +
    "\n" +
    "--------------------------------------------\n";

  std::string const subMenuPrompt = std::string() + "\n" +
    " 1. Add Record.       0. Exit.\n" +
    " 2. Edit Record.\n" +
    " 3. Delete Record.\n";

  bool exit = false;

  while ( !exit )
  {

    int input = GetOptionChoice( adminMenuPrompt );
	
    switch ( input )
    {
    case ( MenuOption_Exit      ) :
      {
        exit = true;
        break;
      }
    case ( MenuOption_Flights   ) : 
    case ( MenuOption_Customers ) :
    case ( MenuOption_Bookings  ) :
    case ( MenuOption_Users     ) :
      {
        AdminSubMenuOption val = AdminSubMenuOption_Unknown;

        while ( val == AdminSubMenuOption_Unknown )
        {
          val = (AdminSubMenuOption)GetOptionChoice( subMenuPrompt );
        }

        if ( val != AdminSubMenuOption_Exit ) 
        {
          switch ( input )
          {
          case ( MenuOption_Flights   ) : 
            AdminFlightMenu( val );
            break;
          case ( MenuOption_Customers ) :
            AdminCustomerMenu( val );
            break;
          case ( MenuOption_Bookings  ) :
            AdminBookingMenu( val );
            break;
          case ( MenuOption_Users     ) :
            AdminUserMenu( val );
            break;
          default:

            ASSERT( false ); // Should never reach this point.
          }
        }

        break;
      }
    default:
      {
        std::cout << "Invalid input.\n";
      }
    }

  } // while

  return InterfaceResult_Abort;
}

AirlineReservationSystem::InterfaceResult AirlineReservationSystem::RegularUserMenu()
{
  enum MenuOption
  {
    MenuOption_Exit,
    MenuOption_Reservation,
    MenuOption_Cancellation,
    MenuOption_Flight,
    MenuOption_Passenger,
    MenuOption_Logout,
    MenuOption_Help
  };

  system("CLS");													//clean screen
  std::string const regularUserMenuPrompt = std::string() +
    "=============================================\n" +
	"\n             Regular User Menu             \n" +
	"\n=============================================\n" +
    "Enter a number corresponding to the operation\nyou wish to perform.\n" +
    "\n" +
    " 1. Reservation          ?. Help\n" +
    " 2. Cancellation         l. Logout\n" +
    " 3. Flight Enquiry       x. Exit\n" +
    " 4. Passenger Enquiry\n" +
    "\n" +
    "---------------------------------------------\n";

  bool exit = false;

  while ( !exit )
  {
    std::cout << regularUserMenuPrompt + "\n> ";
    std::cin.sync();
    std::string strInput;
    std::cin >> strInput;

    int input = GetOptionChoiceWithoutPrintingMenu( strInput );

    if (strInput.compare("l") == 0)
      input = MenuOption_Logout;
    else if (strInput.compare("x") == 0)
      input = MenuOption_Exit;
    else if (strInput.compare("h") == 0)
      input = MenuOption_Help;
    else if (strInput.compare("?") == 0)
      input = MenuOption_Help;

    switch ( input )
    {
    case ( MenuOption_Exit      ) :
      exit = true;
      break;
    case ( MenuOption_Reservation   ) : 
      RegularUserBookingProcedure();
      break;
    case ( MenuOption_Cancellation  ) :
      RegularUserCancellationMenu();
      break;
    case ( MenuOption_Flight        ) :
      RegularUserFlightEnquiryMenu();
      break;
    case ( MenuOption_Passenger     ) :
      RegularUserPassengerEnquiryMenu();
      break;
    case ( MenuOption_Logout ):
      return InterfaceResult_Logout;
    case ( MenuOption_Help ):
      LaunchHelp();
      break;
    default:
      {
        std::cout << "Invalid input.\n";
      }
    }

  } // while
  
  return InterfaceResult_Abort;

}

int AirlineReservationSystem::GetOptionChoice( std::string const& _menuDesc )
{
  std::cout << _menuDesc;

  std::cout << "\n> ";
  std::cin.sync();
  std::string input;
  std::cin >> input;

  int val = -1;

  if ( IsNumeric( input ) )
  {
    val = atoi( input.c_str() );
  }

  return val;
}

int AirlineReservationSystem::GetOptionChoiceWithoutPrintingMenu( std::string input )
{
 
  int val = -1;

  if ( IsNumeric( input ) )
  {
    val = atoi( input.c_str() );
  }

  return val;
}

bool AirlineReservationSystem::ConfirmAction()
{
  int yesNoInput = -1;
  while ( yesNoInput == -1 )
  {
    yesNoInput = GetYesNoChoice( "Are you sure? (Y/N)" );
  }
  return (bool)yesNoInput;
}

int AirlineReservationSystem::GetYesNoChoice( std::string const& _prompt )
{
  std::cout << _prompt;

  std::cout << "\n> ";
  std::cin.sync();
  std::string input;
  std::cin >> input;

  bool val = false;

  if ( input.size() == 1 )
  {
    char c = input.c_str()[0];
    switch (c)
    {
    case 'Y':
    case 'y':
      val = 1;
      break;
    case 'N':
    case 'n':
      val = 0;
      break;
    default:
      val = -1;
    }
  }

  return val;
}
void AirlineReservationSystem::AdminCustomerMenu( AdminSubMenuOption _option )
{
  switch ( _option )
  {
  case ( AdminSubMenuOption_Add    ) :
    {
      AddCustomerProcedure();
      break;
    }
  case ( AdminSubMenuOption_Edit   ) :
    {
      std::list<CustomerRecord const*> customers;
      RecordManager<CustomerRecord>::RecordSet const* rs = m_customerRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        customers.push_back( &(*it) );
      }
      DisplayCustomers( customers );

      int id = GetOptionChoice( "Enter ID of customer record to edit:" );
      CustomerRecord const * r = m_customerRecords.GetRecord( id );

      std::cout << "Current data:\n";
      r->WriteRecord( std::cout );

      std::cout << "\nPlease enter revised data.\n";
      AddCustomerProcedure();
      m_customerRecords.DeleteRecord( id );

      break;
    }
  case ( AdminSubMenuOption_Delete ) :
    {
      std::list<CustomerRecord const*> customers;
      RecordManager<CustomerRecord>::RecordSet const* rs = m_customerRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        customers.push_back( &(*it) );
      }
      DisplayCustomers( customers );

      int id = GetOptionChoice( "Enter ID of customer record to delete:" );

      CustomerRecord const* r = m_customerRecords.GetRecord( id );
      
      std::cout << "Deleting record for: " << r->GetLastName() << ", " << r->GetFirstName() << "\n";

      bool actionConfirmed = ConfirmAction();

      if ( actionConfirmed )
      {
        m_customerRecords.DeleteRecord( id );
        std::cout << "Record deleted.\n";
      } else {
        std::cout << "Record not deleted.\n";
      }

      break;
    }
  default:
    ASSERT( false ); // Should never reach this point.
  }
}

void AirlineReservationSystem::AdminFlightMenu( AdminSubMenuOption _option )
{
  switch ( _option )
  {
  case ( AdminSubMenuOption_Add    ) :
    {
      AddFlightProcedure();
      break;
    }
  case ( AdminSubMenuOption_Edit   ) :
    {
      std::list<FlightRecord const*> flights;
      RecordManager<FlightRecord>::RecordSet const* rs = m_flightRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        flights.push_back( &(*it) );
      }
      DisplayFlights( flights );

      int id = GetOptionChoice( "Enter ID of flight record to edit:" );
      FlightRecord const * r = m_flightRecords.GetRecord( id );

      std::cout << "Current data:\n";
      r->WriteRecord( std::cout );

      std::cout << "\nPlease enter revised data.\n";
      m_flightRecords.DeleteRecord( id );
      AddFlightProcedure();

      break;
    }
  case ( AdminSubMenuOption_Delete ) :
    {
      std::list<FlightRecord const*> flights;
      RecordManager<FlightRecord>::RecordSet const* rs = m_flightRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        flights.push_back( &(*it) );
      }
      DisplayFlights( flights );

      int id = GetOptionChoice( "Enter ID of flight record to delete:" );
      FlightRecord const* r = m_flightRecords.GetRecord( id );
      std::cout << "Deleting record for:" << r->GetFlightCode() << " to " << r->GetDestination() << "\n";

      bool actionConfirmed = ConfirmAction();

      if ( actionConfirmed )
      {
        m_flightRecords.DeleteRecord( id );
        std::cout << "Record deleted.\n";
      } else {
        std::cout << "Record not deleted.\n";
      }

      break;
    }
  default:
    ASSERT( false ); // Should never reach this point.
  }
}

void AirlineReservationSystem::AdminBookingMenu( AdminSubMenuOption _option )
{
  switch ( _option )
  {
  case ( AdminSubMenuOption_Add    ) :
    {
      AddBookingProcedure();
      break;
    }
  case ( AdminSubMenuOption_Edit   ) :
    {
      RecordManager<BookingRecord>::RecordSet const* rs = m_bookingRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        it->WriteRecord( std::cout );
      }

      int id = GetOptionChoice( "Enter ID of booking record to edit:" );
      BookingRecord const * r = m_bookingRecords.GetRecord( id );

      std::cout << "Current data:\n";
      r->WriteRecord( std::cout );

      std::cout << "\nPlease enter revised data.\n";
      AddBookingProcedure();
      m_bookingRecords.DeleteRecord( id );

      break;
    }
  case ( AdminSubMenuOption_Delete ) :
    {
      RecordManager<BookingRecord>::RecordSet const* rs = m_bookingRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        it->WriteRecord( std::cout );
      }

      int id = GetOptionChoice( "Enter ID of booking record to delete:" );
      BookingRecord const * br = m_bookingRecords.GetRecord( id );
      CustomerRecord const * cr = m_customerRecords.GetRecord( br->GetCustomerID() );
      FlightRecord const * fr = m_flightRecords.GetRecord( br->GetCustomerID() );
      std::cout << "Deleting booking record for:" << cr->GetLastName() << ", "
                << cr->GetFirstName() << " on flight "
                << fr->GetFlightCode() << " to "
                << fr->GetDestination() << "\n\n";

      bool actionConfirmed = ConfirmAction();

      if ( actionConfirmed )
      {
        m_bookingRecords.DeleteRecord( id );
        std::cout << "Record deleted.\n";
      } else {
        std::cout << "Record not deleted.\n";
      }
      break;
    }
  default:
    ASSERT( false ); // Should never reach this point.
  }
}

void AirlineReservationSystem::AdminUserMenu( AdminSubMenuOption _option )
{
  switch ( _option )
  {
  case ( AdminSubMenuOption_Add    ) :
    {
      AddUser();
      break;
    }
  case ( AdminSubMenuOption_Edit   ) :
    {
      RecordManager<UserRecord>::RecordSet const* rs = m_userRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        it->WriteRecord( std::cout );
      }

      int id = GetOptionChoice( "Enter ID of user record to edit:" );
      UserRecord const * r = m_userRecords.GetRecord( id );

      std::cout << "Current data:\n";
      r->WriteRecord( std::cout );

      std::cout << "\nPlease enter revised data.\n";
      AddUser();
      m_userRecords.DeleteRecord( id );

      break;
    }
  case ( AdminSubMenuOption_Delete ) :
    {
      RecordManager<UserRecord>::RecordSet const* rs = m_userRecords.GetRecordSet();
      for ( auto it = rs->begin(); it != rs->end(); ++it )
      {
        it->WriteRecord( std::cout );
      }

      int id = GetOptionChoice( "Enter ID of user record to delete:" );
      UserRecord const * r = m_userRecords.GetRecord( id );

      bool actionConfirmed = ConfirmAction();

      if ( actionConfirmed )
      {
        m_userRecords.DeleteRecord( id );
        std::cout << "Record deleted.\n";
      } else {
        std::cout << "Record not deleted.\n";
      }

      break;
    }
  default:
    ASSERT( false ); // Should never reach this point.
  }
}

void AirlineReservationSystem::AddUser()
{
  std::string username;
  std::string password;
  std::cout << "Enter username:\n> ";
  std::cin.sync();
  std::cin >> username;
  std::cout << "Enter password:\n> ";
  std::cin.sync();
  std::cin >> password;

  bool valid = false;
  int input;
  while ( !valid )
  {
    std::string prompt( "Enter 1 to grant user administrator rights, 0 otherwise.\n> " );
    input = GetOptionChoice( prompt );
    if ( input == 1 || input == 0 )
    {
      valid = true;
    }
  }
  bool isAdmin = (bool)input;
  UserRecord ur( username, password, isAdmin );
  m_userRecords.AddRecord( ur );
}


//===============================================================================
//                                Customer Enquiry
//===============================================================================
void AirlineReservationSystem::RegularUserPassengerEnquiryMenu()
{
  bool valid = false;
  int intOption = 0;   
	std::string option = "";

	while ( !valid )
	{
		std::cout << "\nPlease select if you want to search by Booking Number or by Customer Name\n";
		std::cout << "1. By Booking Number\n2. By Customer Name\n";
  std::cout << "> ";
  std::cin >> option;

		CheckReturningToMainMenu(REGULAR_USER_MENU, option);		//check if user enters 'quit'

		if ( AirlineRes::IsNumeric( option ) )
		{
			// Convert the flight id into an int
			intOption = atoi(  option.c_str() );
			if ((intOption == 1 || intOption == 2))   
			{
				valid = true;
			}
			else 
			{
				std::cout << "Invalid Input. Please enter either 1 or 2.\n";
			}
		}  
		else
		{
      std::cout << "Invalid Input. Please enter a numeric value.\n";
		}
	}

  RegularUserPassengerEnquirySearch(intOption);
}

//Ask user to select search type
void AirlineReservationSystem::RegularUserPassengerEnquirySearch(int option)
{
  switch (option) 
  {
    case SEARCH_BY_BOOKING_NUMBER :  
      RegularUserPassengerEnquirySearchByBookingNumber();        //search by booking number
      break;
    case SEARCH_BY_NAME : 
      RegularUserPassengerEnquirySearchByName();            //search by customer's name
      break;
    default : 
      std::cout << "Invalid Input.\n";
      RegularUserPassengerEnquiryMenu();                //... ask again
      break;
  }
}

//Search a customer by booking number
void AirlineReservationSystem::RegularUserPassengerEnquirySearchByBookingNumber()
{
  //Get customer's booking number
  std::string strCustomerBookingNumber = "";
  int customerBookingNumber = -1;

    bool valid = false;

	while ( !valid )
	{
        std::cout << "\nPlease enter the Customer's Booking Number:\n";  
  std::cout << "> ";
		std::cin >> strCustomerBookingNumber;

		CheckReturningToMainMenu(REGULAR_USER_MENU, strCustomerBookingNumber);

		if ( AirlineRes::IsNumeric( strCustomerBookingNumber ) )
		{
			// Convert the flight id into an int
			customerBookingNumber = atoi(  strCustomerBookingNumber.c_str() );
			valid = true;
		}  
		else
		{
      std::cout << "\nInvalid Input. Please enter a numeric value.\n";
		}
	}

  //Find the customer ID from the booking records
  bool boolCustomerBookingNumberFound = false;
  int customerID = -1;
  for ( auto it = m_bookingRecords.GetRecordSet()->begin(); it != m_bookingRecords.GetRecordSet()->end(); ++it )
  {
    if (it->GetID() == customerBookingNumber)
    {
      boolCustomerBookingNumberFound = true;    //booking number found
      customerID = it->GetCustomerID();      //save customer ID
      break;
    }
  }

  //Initialise some strings for customer's name and passport
  std::string customerFirstName = "";
  std::string customerLastName = "";
  std::string customerPassport = "";

  if (boolCustomerBookingNumberFound)
  {
    //find the customer's info since we know her ID
    for ( auto it = m_customerRecords.GetRecordSet()->begin(); it != m_customerRecords.GetRecordSet()->end(); ++it )
    {
      if (it->GetID() == customerID)
      {
        customerFirstName = it->GetFirstName();    //save customer's first name
        customerLastName = it->GetLastName();    //save customer's last name
        customerPassport = it->GetPassportNo();    //save customer's passport number
        break;
      }
    }
    RegularUserPassengerEnquiryOutput(customerID,    //print the list with her flights
                      customerFirstName + " " +  customerLastName,
                      customerPassport);
  }
  else
  {
    std::cout << "The booking number entered is not valid.\n";
    RegularUserPassengerEnquiryAsk();                //ask the user if she wants to make 
                                    //a new enquiry
  }
}

//Search a customer by name
void AirlineReservationSystem::RegularUserPassengerEnquirySearchByName()
{
  //Get cusromer's first name
  std::cout << "\nPlease enter the Customer's First Name" << std::endl;
  std::cout << "> "; 
  std::string customerFirstName="";
  std::cin >> customerFirstName;
  
  //Get customer's last name
  std::cout << "Please enter the Customer's Last Name" << std::endl;
  std::cout << "> "; 
  std::string customerLastName="";
  std::cin >> customerLastName;

  
  //Do a quick check and see if there is any customer with that name
  auto customerRS = m_customerRecords.GetRecordSet();
  bool boolCustomerFound = false;                      //false if there is there is no customer with that name
  for ( auto it = customerRS->begin(); it != customerRS->end(); ++it )
  {
    if ( ( it->GetLastName() == customerLastName ) && ( it->GetFirstName() == customerFirstName ) )
    {
      boolCustomerFound = true;      //customer found -> make boolean variable true
      break;
    }
  }

  if (!boolCustomerFound)                            //if the customer can not been found
  {
    std::cout << "There was no customer found with that name.\n";    //print a "no found" message
    RegularUserPassengerEnquiryAsk();                    //ask the user if she wants to make a new customer enquiry
  }

    //Print a header explaining the data of each column
  std::cout << "-------------------------------------------------------------" << std::endl;
  std::cout << "Option\tFull Name\t\tPassport\tDate of Birth\n" << std::endl;
  std::cout << "-------------------------------------------------------------" << std::endl;

  //Look for customers with that first and last name, and display them, with their info
  std::list <CustomerRecord const*> matches;
  int option = 0;

  //In this vector the ID of each customer of the output list is going to be added.
  std::vector <int> vectorCustomersIDs;
  std::vector <std::string> vectorCustomersPassports;

  
  for ( auto it = customerRS->begin(); it != customerRS->end(); ++it )
  {
    if ( ( it->GetLastName() == customerLastName ) && ( it->GetFirstName() == customerFirstName ) )
    {    
      vectorCustomersIDs.push_back(it->GetID());          //add the ID of the matched customer into the vector
      vectorCustomersPassports.push_back(it->GetPassportNo());  
      std::cout << ++option << "\t";                //increase the option number by one
      std::cout << it->GetFirstName() << " ";            //print the first name of the customer
      std::cout << it->GetLastName() << "\t\t";          //print the second name of the customer
      std::cout << it->GetPassportNo() << "\t\t";          //print the passport number of the customer
      std::cout << it->GetDateOfBirth().GetDay() << "/" <<    //print the date of birth of the customer
        it->GetDateOfBirth().GetMonth() << "/" <<
        it->GetDateOfBirth().GetYear() << std::endl;
    }
  }

  for ( auto it = matches.begin(); it != matches.end(); ++it )
  {
    (*it)->WriteRecord( std::cout );
    std::cout << "\n";
  }


  //If the option variable remains 0 (initial value), that means that there 
  //is no matching customer. In that case print a message, else ask the 
  //user to select the customer.
  if ( option == 0 )
  {
    std::cout << "There was no customer found with that name.\n"; 
  }
  else 
  {
    std::string strSelectedCustomer = "9999999999999999";

	bool valid = false;

    while (!valid)
    {
      std::cout << "Please select the customer from the list.\n"
              << "If the correct Customer is not displayed please enter 0.\n> ";
      std::cin >> strSelectedCustomer;

	  CheckReturningToMainMenu(REGULAR_USER_MENU, strSelectedCustomer); //check if user wants to return to main menu
	  
	  int selectedCustomer = atoi(  strSelectedCustomer.c_str() );

		  if ( (selectedCustomer > option) )
        std::cout << selectedCustomer << " is not a valid option! Please select a valid option." << std::endl;
      else if (selectedCustomer != 0)
        RegularUserPassengerEnquiryOutput(vectorCustomersIDs[selectedCustomer-1], 
                          customerFirstName + " " +  customerLastName,
                          vectorCustomersPassports[selectedCustomer-1]);
    }  
  }
}


void AirlineReservationSystem::RegularUserPassengerEnquiryOutput(int customerID, 
                                 std::string customerName,
                                 std::string customerPassport)
{
  
  auto bookingRS = m_bookingRecords.GetRecordSet();
  int option = 0;

  //Print a header explaining the data of each column
  std::cout << "-------------------------------------------------------------" << std::endl;
  std::cout << "Name: " << customerName << " \t Passport: " << customerPassport << std::endl;
  std::cout << "-------------------------------------------------------------" << std::endl;
  std::cout << "Flight Code\tDate\t\tStatus\t\tClass\n" << std::endl;
  std::cout << "-------------------------------------------------------------" << std::endl;
  

  //check if the customer has any bookings
  bool boolBookingFound = false;                      //false when no booking can not be found for the customer            
  for ( auto it = bookingRS->begin(); it != bookingRS->end(); ++it )
  {
    if ( ( it->GetCustomerID() == customerID )  )            //when the system finds a booking for the customer ID
    {
      boolBookingFound = true;                    //makes the boolean variable true
      std::cout << RegularUserPassengerEnquiryOutputGetFlightCode(it->GetFlightID()) << "\t\t";        //prints the flight code
      std::cout << RegularUserPassengerEnquiryOutputGetFlightTimeDate(it->GetFlightID()).GetDay() << "/"    //the flight date
            << RegularUserPassengerEnquiryOutputGetFlightTimeDate(it->GetFlightID()).GetMonth() << "/"
            << RegularUserPassengerEnquiryOutputGetFlightTimeDate(it->GetFlightID()).GetYear() << "\t";
      std::cout << GetBookingStatusString(it->GetBookingStatus()) << "\t";                  //the booking status and
      std::cout << GetBookingClassString(it->GetBookingClass()) << std::endl;                  //the booking class
    }
    
  }

  //If no booking could not be found for the customer, a "no found" message is being displayed on the screen
  if (!boolBookingFound)
  {
    std::cout << "There was no customer found with the name provided.\n";
  }

  //ask the user if she wants to make a new customer enquiry
  RegularUserPassengerEnquiryAsk();
}

//Return the flight code of a given flight ID
std::string AirlineReservationSystem::RegularUserPassengerEnquiryOutputGetFlightCode(int flightID){
  
  std::string flightCode = "Unknown flight Code";

  for ( auto it = m_flightRecords.GetRecordSet()->begin(); it != m_flightRecords.GetRecordSet()->end(); ++it )
  {
    if ( ( it->GetID() == flightID )  )
    {
      flightCode = it->GetFlightCode();
    }
  }
  
  return flightCode;
}

//Return the flight time and date of a given flight ID
TimeDate AirlineReservationSystem::RegularUserPassengerEnquiryOutputGetFlightTimeDate(int flightID){
  
  TimeDate flightTimeDate;

  for ( auto it = m_flightRecords.GetRecordSet()->begin(); it != m_flightRecords.GetRecordSet()->end(); ++it )
  {
    if ( ( it->GetID() == flightID )  )
    {
      flightTimeDate = it->GetFlightTimeDate();
    }
  }
  
  return flightTimeDate;
}

//Ask if the user wants to make a new Passenger Enquiry or not
void AirlineReservationSystem::RegularUserPassengerEnquiryAsk()
{
  std::string answer = "";
	bool valid = false;

	while ( !valid )
  {
		std::cout << "\nWould you like to make a new Customer Enquiry (Y/N)?" << std::endl << "> "; //ask the user
		std::cin >> answer;

		//CheckReturningToMainMenu(REGULAR_USER_MENU, answer);

		answer = ConvertToLower( answer );
		if ( (answer.compare(ANSWER_YES) == 0) || (answer.compare(ANSWER_NO) == 0) )
		{
			valid = true;
		}
		else
		{
			std::cout << "Invalid Input. Please enter either Y or N.\n"; 		
		}
	}
    if (answer.compare(ANSWER_YES) == 0)      
    RegularUserPassengerEnquiryMenu();                //if yes -> make a new flight enquiry
  else
      RegularUserMenu();                            //if no -> return to the user main menu
}  
    

//-------------------------------------------------------------------------------
//                             End of Customer Enquiry
//===============================================================================



//===============================================================================
//                             Start of Flight Enquiry
//-------------------------------------------------------------------------------
void AirlineReservationSystem::RegularUserFlightEnquiryMenu()
{
	bool valid = false;
	int intOption = 0;
	std::string strOption = "";

	while ( !valid )
	{
  std::cout << "\nPlease select if you want to search by Flight Number or by Destination\n";
  std::cout << "1. By Flight Number\n2. By Destination" << std::endl;
  std::cout << "> ";
		std::cin >> strOption;

		CheckReturningToMainMenu(REGULAR_USER_MENU, strOption);

		if ( AirlineRes::IsNumeric( strOption ) )
		{
			// Convert the flight id into an int
			intOption = atoi(  strOption.c_str() );
			if ((intOption == 1 || intOption == 2))   
			{
				valid = true;
			}
			else
			{
				std::cout << "Invalid Input.\n";
			}
		}  
		else
		{
			std::cout << "Invalid Input.\n";
		}
	}

	RegularUserFlightEnquirySearch(intOption);
}

//Ask user to select search type
void AirlineReservationSystem::RegularUserFlightEnquirySearch(int option)
{
  switch (option) 
  {
    case SEARCH_BY_FLIGHT_NUMBER :  
      RegularUserFlightEnquirySearchByFlightNumber();       //search by flight number
      break;
    case SEARCH_BY_DESTINATION : 
      RegularUserFlightEnquirySearchByDestination();		//search by destination
      break;
    default : 
      std::cout << "\n" << option							//print an error message and...
            << " is not a valid option! Please select 1 or 2." 
            << std::endl;
      RegularUserFlightEnquiryAsk();                //... ask her again
      break;
  }
}

//Search a flight by the fligh number
void AirlineReservationSystem::RegularUserFlightEnquirySearchByFlightNumber()
{
  //Get the flight number
  std::cout << "\nPlease enter the Flight Number:" << std::endl;  
  std::cout << "> ";
  std::string flightCode = "12345";
  std::cin >> flightCode;

  
  //check the flight code lenght. If it is not 5 display a non valid message
  if (flightCode.length() !=5 )
  {
    std::cout << "The flight code you entered is not valid. The flight code is a 5 digit code." << std::endl;
    RegularUserFlightEnquiryAsk();
  }
  

  //check if the first two characters are alphabetic
  if ( (isalpha(flightCode[0]) == 0 ) || (isalpha(flightCode[1]) == 0) )
  {
    std::cout << "The flight code you entered is not valid. The first two digits must be alphabetic. ";
    
    if ( (isdigit(flightCode[2]) == 0 ) || (isdigit(flightCode[3]) == 0) || (isdigit(flightCode[4]) == 0))
    {
      std::cout << "The last three digits must be numeric";
    }
    
    std::cout << std::endl;
    RegularUserFlightEnquiryAsk();
  }

  //check if the last three characters are numeric
  if ( (isdigit(flightCode[2]) == 0 ) || (isdigit(flightCode[3]) == 0) || (isdigit(flightCode[4]) == 0))
  {
    std::cout << "The flight code you entered is not valid. The last three digits must be numeric." << std::endl;
    RegularUserFlightEnquiryAsk();
  }

  RegularUserFlightEnquiryOutput(flightCode);
    

  
}

//Search a flight by the destination
void AirlineReservationSystem::RegularUserFlightEnquirySearchByDestination()
{
	//Get the destination
	std::cout << "\nPlease enter destination:" << std::endl;  
	std::cout << "> ";
	std::string flightDestination = "destination";
	std::cin >> flightDestination;

	std::string destination;
	std::list<FlightRecord const*> flight_shortlist;

    while ( flight_shortlist.size() == 0 )
	{
        // Get the destination from the user 
        destination = ConvertToLower( flightDestination );
				
        // Populate the shortlist based on the destination
        flight_shortlist = GetFlightShortList( destination );
        if (flight_shortlist.size() == 0)
        {
          std::cout << "No flights avaliable to this destination. Please enter a new destination.\n";
        }
      }

    // Display the flights to the user
    std::cout << "\nBelow is a list of flights to " << destination << ":\n";
    DisplayFlights( flight_shortlist );

    // Set the value for flight id
    int flight_id = GetFlightIDChoice();
	
	std::string flightCode = "AA000";
	
	auto flights = m_flightRecords.GetRecordSet();

	// Match the Flight ID and get the number of seats on the flight
	for ( auto it = flights->begin(); it != flights->end(); ++it )
	{
		if ( it->GetID() == flight_id )
		{
			flightCode = it->GetFlightCode();
		}
	}

	//make enquiry
	RegularUserFlightEnquiryOutput(flightCode);


}

void AirlineReservationSystem::RegularUserFlightEnquiryOutput(std::string flightCode)
{
  //check if the flight code exists
  int flightID = 9999999;
  bool boolFlightCodeFound = false;
  for ( auto it = m_flightRecords.GetRecordSet()->begin(); it != m_flightRecords.GetRecordSet()->end(); ++it )
  {
    if ( it->GetFlightCode().compare(flightCode) == 0 )
    {
      boolFlightCodeFound = true;
      flightID = it->GetID();
      break;
    }
  }

  if ( !boolFlightCodeFound )
  {
    std::cout << "No flight was found with the Flight Code provided.\n";
    RegularUserFlightEnquiryAsk();
  }

  //print the flight info
  for ( auto it = m_flightRecords.GetRecordSet()->begin(); it != m_flightRecords.GetRecordSet()->end(); ++it )
  {
    if ( it->GetFlightCode().compare(flightCode) == 0 )
    {
      std::cout << "---------------------Flight Information----------------------" << std::endl;
      std::cout << "Flight Code: " << it->GetFlightCode() 
        << "\t\tDate: " << it->GetFlightTimeDate().GetDay() << "/"
        << it->GetFlightTimeDate().GetMonth() << "/"
        << it->GetFlightTimeDate().GetYear() << std::endl;
	  std::cout << "Destination: " << it->GetDestination()
        << "\t\tTime: " << it->GetFlightTimeDate().GetHour() << ":"
        << it->GetFlightTimeDate().GetMinute() << std::endl;
	  std::cout << "Seats:       " << it->GetNumSeats() << std::endl; 
      std::cout << "-------------------------------------------------------------" << std::endl;
      break;
    }
  }

  std::vector <int> totalPassengersIDs;
  std::vector <int> totalStatuses;
  std::vector <int> totalClasses;

  //find all the bookings of the selected flight
  for ( auto it = m_bookingRecords.GetRecordSet()->begin(); it != m_bookingRecords.GetRecordSet()->end(); ++it )
  {
    if ( it->GetFlightID() == flightID )
    {
      totalPassengersIDs.push_back(it->GetCustomerID());
      totalStatuses.push_back(it->GetBookingStatus());
      totalClasses.push_back(it->GetBookingClass());
    }
  }


  std::string passengerName = "";
  std::vector <std::string> totalPassengersNames;
  std::vector <std::string> totalPassengersPassports;
  

  //map each id to name and passport
  for ( uint i = 0; i < totalPassengersIDs.size(); ++i )
  {
    for ( auto it = m_customerRecords.GetRecordSet()->begin(); it != m_customerRecords.GetRecordSet()->end(); ++it )
    {
      if ( totalPassengersIDs[i] == it->GetID() )
      {
        totalPassengersNames.push_back( it->GetFirstName() + " " + it->GetLastName() );
        totalPassengersPassports.push_back( it->GetPassportNo() );
        break;
      }
    }
  }



  //Print the passenger list
  std::cout << "\n---------------------- Passenger List -----------------------" << std::endl;
  for (uint i = 0; i < totalPassengersIDs.size(); ++i)
  {
    if ( (totalStatuses[i] == 0) && (totalClasses[i] == 0) )
    {
      std::cout << totalPassengersNames[i] 
            << "\t" << totalPassengersPassports[i]
            << "\t\t" << "First"
            << std::endl;
    }
  }

  for (uint i = 0; i < totalPassengersIDs.size(); ++i)
  {
    if ( (totalStatuses[i] == 0) && (totalClasses[i] == 1) )
    {
      std::cout << totalPassengersNames[i] 
            << "\t" << totalPassengersPassports[i]
            << "\t\t" << "Economy"
            << std::endl;
    }
  }

  //Print the waiting list
  std::cout << std::endl;
  std::cout << "\n----------------------- Waiting List ------------------------" << std::endl;
  for (uint i = 0; i < totalPassengersIDs.size(); ++i)
  {
    if ( (totalStatuses[i] == 1) && (totalClasses[i] == 0) )
    {
      std::cout << totalPassengersNames[i] 
            << "\t" << totalPassengersPassports[i]
            << "\t\t" << "First"
            << std::endl;
    }
  }

  for (uint i = 0; i < totalPassengersIDs.size(); ++i)
  {
    if ( (totalStatuses[i] == 1) && (totalClasses[i] == 1) )
    {
      std::cout << totalPassengersNames[i] 
            << "\t" << totalPassengersPassports[i]
            << "\t\t" << "Economy"
            << std::endl;
    }
  }
  RegularUserFlightEnquiryAsk();
}

//Ask if the user wants to make a new Flight Enquiry or not
void AirlineReservationSystem::RegularUserFlightEnquiryAsk()
{
  std::string answer = "";
	bool valid = false;

	while ( !valid )
  {
		std::cout << "\nWould you like to make a new Flight Enquiry (Y/N)?" << std::endl << "> "; //ask the user
		std::cin >> answer;

		CheckReturningToMainMenu(REGULAR_USER_MENU, answer);

		answer = ConvertToLower( answer );
		if ( (answer.compare(ANSWER_YES) == 0) || (answer.compare(ANSWER_NO) == 0) )
		{
			valid = true;
		}
		else
		{
			std::cout << "Invalid Input. Please enter either Y or N.\n"; 
		}
	}
    if (answer.compare(ANSWER_YES) == 0)      
      RegularUserFlightEnquiryMenu();                //if yes -> make a new flight enquiry
  else
      RegularUserMenu();                          //if no -> return to the user main menu
}  


//-------------------------------------------------------------------------------
//                             End of Flight Enquiry
//===============================================================================



//===============================================================================
//                                Other functions
//-------------------------------------------------------------------------------
std::string AirlineReservationSystem::GetBookingStatusString(int bookingStatus)
{
  std::string strBookingStatus = "";
  switch (bookingStatus)
  {
    case 0:
      strBookingStatus = "Confirmed";
      break;
    case 1:
      strBookingStatus = "Reserved";
      break;
    default:
      strBookingStatus = "Unknown";
      break;
  }

  return strBookingStatus;

}

std::string AirlineReservationSystem::GetBookingClassString(int bookingClass)
{
  std::string strBookingClass = "";

  switch (bookingClass)
  {
    case 0:
      strBookingClass = "First";
      break;
    case 1:
      strBookingClass = "Economy";
      break;
    default:
      strBookingClass = "Unknown";
      break;
  }

  return strBookingClass;

}

	//check if
void AirlineReservationSystem::CheckReturningToMainMenu(int menu, std::string strInput)
{
	if ( strInput.compare(MAIN_MENU_COMMAND) == 0 )
	{
		if (menu == ADMIN_USER_MENU)
			AdminMenu();
		else if (menu == REGULAR_USER_MENU)
			RegularUserMenu();
	}		
}


void AirlineReservationSystem::ExitConfirmation(int menu)
{
	while ( 1 )
	{
		std::cout << "Are you sure you want to exit (Y/N)?\n> ";	//ask user if she wants to exit
		std::string strInput = "";
		std::cin >> strInput;										//get input
		
		//check if input is Y or y
		if ( (strInput.compare("Y") == 0) || (strInput.compare("y") == 0) )
		{
			Shutdown();
			exit (1);
		}

		//check if input is N or n
		else if ( (strInput.compare("N") == 0) || (strInput.compare("n") == 0) )
		{
			if ( menu == ADMIN_USER_MENU )			//check if the user is an admin or a regular on
				AdminMenu();						//and return the corresponding menu
			else if ( menu == REGULAR_USER_MENU )
				RegularUserMenu();
			else 
				break;
		}
		
		//if the input is neither Y/y or N/n tell the user that the input is invalid
		else 
			std::cout << "The input is invalid\n";	
	}
}

//-------------------------------------------------------------------------------
//                              End of other functions
//===============================================================================

//===============================================================================
//                             Start of Admin Add Functions
//-------------------------------------------------------------------------------
int AirlineReservationSystem::AddCustomerProcedure()
{
  // Customer detail variables
  std::string first_name;
  std::string last_name;
  std::string passport_number;
  std::string temp_dob;
  std::string email;
  std::string phone_no;

  std::cout << "Enter the First Name of the customer: ";
  std::cin.sync();
  std::cin >> first_name;
  std::cout << "Enter the Last Name of the customer: ";
  std::cin.sync();
  std::cin >> last_name;
  std::cout << "Enter the Passport of the customer: ";
  std::cin.sync();
  std::cin >> passport_number;
  std::cout << "Enter the Date of Birth of the customer (in the format DDMMYYYY): ";
  std::cin.sync();
  std::cin >> temp_dob;
  TimeDate date_of_birth( temp_dob );
  std::cout << "Enter the Email Address of the customer: ";
  std::cin.sync();
  std::cin >> email;
  std::cout << "Enter the Phonenumber of the customer: ";
  std::cin.sync();
  std::cin >> phone_no;
  // TODO - Validation on user inputs

  // Create new customer and add to the customer records
  CustomerRecord customer( passport_number, first_name, last_name, date_of_birth, email, phone_no );
  m_customerRecords.AddRecord ( customer );
  std::cout << "\nCustomer successfully added.\n";
  
  // Get the customer (as before it is added there is no id)
  // Assumes passport number is unique
  auto customers = m_customerRecords.GetRecordSet();
  int customer_id = 0;

  for ( auto it = customers->begin(); it != customers->end(); ++it )
  {
      if ( it->GetPassportNo() == passport_number )
      {
          int customer_id = it->GetID();
          break;
      }
  }

  return customer_id;
}

void AirlineReservationSystem::AddBookingProcedure()
{
  // booking detail variables
  int flight_id = GetBookingFlightID();
  int customer_id = GetBookingCustomerID();
  BookingRecord::BookingStatus booking_status = GetBookingStatus(); 
  BookingRecord::BookingClass booking_class = GetBookingClass();

  // Create new booking and add to the booking records
  BookingRecord booking( flight_id, customer_id, booking_status, booking_class );
  m_bookingRecords.AddRecord ( booking );
  std::cout << "\nBooking successfully added.\n";
}

BookingRecord::BookingStatus AirlineReservationSystem::GetBookingStatus()
{
  std::string const status_choice_string = std::string() +
  "Please select a status for this booking:\n" +
    " 1. Confirmed.\n" +
    " 2. Reserved.\n";

  int status_choice =  GetOptionChoice( status_choice_string );

  if ( status_choice == 1 )
  {
    return BookingRecord::BookingStatus_Confirmed;
  }
  else
  {
    return BookingRecord::BookingStatus_Reserved;
  }
}

BookingRecord::BookingClass AirlineReservationSystem::GetBookingClass()
{
	while (true){
    std::cout <<
      "\nPlease select a class for this booking:\n" <<
      " 1. First Class.\n" <<
      " 2. Economy Class.\n> ";

    std::string strInput = "0000";
    std::cin.sync();
    std::cin >> strInput;

    CheckReturningToMainMenu(REGULAR_USER_MENU, strInput);

    int class_choice =  GetOptionChoiceWithoutPrintingMenu( strInput );

    if ( class_choice == 1 )
      return BookingRecord::BookingClass_First;
    else if ( class_choice == 2 )
      return BookingRecord::BookingClass_Economy;
    else 
      std::cout << "\nThe input is invalid. Please select 1 or 2.\n";
  }
}

void AirlineReservationSystem::LaunchHelp()
{
  std::cout << "Launching help..\n";
  system( USER_GUIDE_COMMAND );
}

int AirlineReservationSystem::GetBookingCustomerID()
{
  int customer_id = 0;
  bool valid = false;

  while ( !valid )
  {
    std::cout << "Please enter a Customer ID.\n";
    std::cout << "> ";
    std::cin.sync();
    std::cin >> customer_id;

    if ( IsCustomerIDValid( customer_id ) )   
    {
      valid = true;
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }

  return customer_id;
}

int AirlineReservationSystem::GetBookingFlightID()
{
  int flight_id = 0;
  bool valid = false;

  while ( !valid )
  {
    std::cout << "Please enter a Flight ID.\n";
    std::cout << "> ";
    std::cin.sync();
    std::cin >> flight_id;

    if ( IsFlightIDValid( flight_id ) )   
    {
      valid = true;
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }

  return flight_id;
}

void AirlineReservationSystem::AddFlightProcedure()
{
  // Flight detail variables
  std::string flight_code;
  int num_seats;
  std::string temp_date;
  std::string temp_time;
  std::string destination;

  std::cout << "Enter the Flight Code: ";
  std::cin.sync();
  std::cin >> flight_code;
  std::cout << "Enter the Number of Seats on the flight: ";
  std::cin.sync();
  std::cin >> num_seats;
EnterDate:
  std::cout << "Enter the Date of the flight (in the format DDMMYYYY): ";
  std::cin.sync();
  std::cin >> temp_date;
  // Validate and store time/date.
  if ( !IsNumeric( temp_date ) || !( temp_date.size() == 8 ) )
  {
    goto EnterDate;
  }
  int const day   = atoi( temp_date.substr( 0, 2 ).c_str() );
  int const month = atoi( temp_date.substr( 2, 2 ).c_str() );
  int const year  = atoi( temp_date.substr( 4, 4 ).c_str() );

  if ( !( day > 0 && day <= 31 &&
          month > 0 && month <= 12 &&
          year > 1990 && year <= 3000
     )  )
  {
    goto EnterDate;
  }

EnterTime:
  std::cout << "Enter the Time of the flight (in the format HHMM): ";
  std::cin.sync();
  std::cin >> temp_time;

  if ( !IsNumeric( temp_time ) || !( temp_time.size() == 4 ) )
  {
    goto EnterTime;
  }

  int hour   = atoi( temp_time.substr( 0, 2 ).c_str() );
  int minute = atoi( temp_time.substr( 2, 2 ).c_str() );
  if ( !( ( hour   >= 0 && hour   < 24 ) &&
    ( minute >= 0 && minute < 60 )    ) )
  {
    goto EnterTime;
  }


  TimeDate time( temp_date, temp_time );
  std::cout << "Enter the Destination of the flight: ";
  std::cin.sync();
  std::cin >> destination;
  // TODO - Validation on user inputs

  // Create new flight and add to the flight records
  FlightRecord temp_flight( flight_code, num_seats, time, destination );
  int err = m_flightRecords.AddRecord( temp_flight );
  std::cout << "\nFlight successfully added.\n";
}

void AirlineReservationSystem::AddUserProcedure()
{
  // Customer detail variables
  std::string username;
  std::string password;
  std::string is_admin_temp;
  bool is_admin;

  std::cout << "Enter the Username: ";
  std::cin.sync();
  std::cin >> username;
  std::cout << "Enter the Password of the user: ";
  std::cin.sync();
  std::cin >> password;
  while ( is_admin_temp != "Y" && is_admin_temp != "N" )
  {
      std::cout << "Is the user an Admin User? (Y/N): ";
      std::cin.sync();
      std::cin >> is_admin_temp;
      if ( is_admin_temp != "Y" && is_admin_temp != "N" )
      {
          std::cout << "Invalid input!\n";
      }
  }
  // Convert the user input into a boolean for is_admin
  is_admin = ParseAdmin( is_admin_temp );

  // Create new user and add to the user records
  UserRecord temp_user( username, password, is_admin );
  m_userRecords.AddRecord ( temp_user );
  std::cout << "\nUser successfully added.\n";
}

bool AirlineReservationSystem::ParseAdmin( std::string admin_string )
{
  if ( admin_string == "Y" )
  {
      return true;
  }
  else
  {
      return false;
  }
}
//-------------------------------------------------------------------------------
//                             End of Admin Add Functions
//===============================================================================

//===============================================================================
//                             Start of Reservation Functions
//-------------------------------------------------------------------------------
void AirlineReservationSystem::RegularUserBookingProcedure()
{
  bool cancel_booking = false;
  std::string booking_destination = "";
  std::list<FlightRecord const*> flight_shortlist;

  while ( !cancel_booking )
  {
      while ( flight_shortlist.size() == 0 )
      {
        // Get the destination from the user 
        booking_destination = ConvertToLower( GetBookingDestination() );
				
        // Populate the shortlist based on the destination
        flight_shortlist = GetFlightShortList( booking_destination );
        if (flight_shortlist.size() == 0)
        {
          std::cout << "No flights avaliable to this destination. Please enter a new destination.\n";
        }
      }

      // Display the flights to the user
      std::cout << "\nBelow is a list of flights to " << booking_destination << ":\n";
      DisplayFlights( flight_shortlist );

      // Set the value for flight id
      int flight_id = GetFlightIDChoice();
      // Get the class choice from the user
      BookingRecord::BookingClass booking_class = GetBookingClass();
      BookingRecord::BookingStatus booking_status;

      bool book_reserve = false;
      // If there is space on the flight in that class
      if ( IsSpace( flight_id, booking_class ) )
      {
        // Set the booking status to confirmed
        booking_status = BookingRecord::BookingStatus_Confirmed;
        std::cout << "There is space availiable on this flight.\n";
      }
      else 
      {
        std::cout << "There is no space in the selected class.\n";
        // Change the booking class
        booking_class = SwitchBookingClass( booking_class );
        // Check is there is space in the alternative class
        if ( IsSpace( flight_id, booking_class ) )
        {
          if ( WantToBookAlternativeClass() )
          {
            // Ste the booking status to confirmed
            booking_status = BookingRecord::BookingStatus_Confirmed;
          }
          else
          {
            // End Booking Process
            cancel_booking = true;
            break;
          }
        }
        else
        {
          std::cout << "There is no space in the alternative class for this flight.\n";
          if ( WantToBookReserve() )
          {
            // Indicate the need to get a reserve class choice from the user
            book_reserve = true;
          }
          else
          {
            cancel_booking = true;
            break;
          }
        }
      }

      // If the user wish to book a reserve seat
      if ( book_reserve )
      {
        // Get the class for which the customer wishes to reserve a seat
        booking_class = GetBookingClass();
        // Set the status to reserve
        booking_status = BookingRecord::BookingStatus_Reserved;
      }

      // Get customer information for the booking
      int customer_id = 0;
      // Check if the passenger is already registered
      if ( AlreadyRegistered() )
      {
        // Get the surname of the customer
        std::string surname = ConvertToLower( GetCustomerSurname() );

        // Populate the shortlist based on the destination
        std::list<CustomerRecord const*> customer_shortlist = GetCustomerList( surname );

        // Display the customers to the user
        if ( customer_shortlist.size() == 0)
        {
          std::cout << "There are no customers with that surname.";
        }
        else
        {
          std::cout << "\nBelow is a list of customers with the Last Name - " << surname << ":\n";
          DisplayCustomers( customer_shortlist );
        }

        customer_id = GetCustomerIDChoice();
      }
      else
      {
        // Add a new customer
        customer_id = AddCustomerProcedure();
      }

      // Check customer is not already booked on a flight for this day;
      auto bookingRS = m_bookingRecords.GetRecordSet();
      auto flightRS = m_flightRecords.GetRecordSet();

      bool alreadyOnFlightThatDay = false;

      for ( auto it = bookingRS->begin(); it != bookingRS->end(); ++it )
      {
        if ( it->GetCustomerID() == customer_id )
        {
          auto fr = m_flightRecords.GetRecord( it->GetFlightID() );
          TimeDate date = fr->GetFlightTimeDate();
          auto bookingFlightRecord = m_flightRecords.GetRecord( flight_id );
          TimeDate bookingDate = bookingFlightRecord->GetFlightTimeDate();
          if ( date.GetDay()   == bookingDate.GetDay() &&
               date.GetMonth() == bookingDate.GetMonth() &&
               date.GetYear()  == bookingDate.GetYear() )
          {
            alreadyOnFlightThatDay = true;
          }
        }
      }

      if ( alreadyOnFlightThatDay )
      {
        cancel_booking = true;
        std::cout << "Customer already booked on a flight that day.\n";
        break;
      }

      // Create and store the new booking
      BookingRecord booking( flight_id, customer_id, booking_status, booking_class);
      m_bookingRecords.AddRecord ( booking );
      std::cout << "Successfully added the new booking to the system.\n";
      break;
    }
    // If the booking has been cancelled then display the message to the user 
    if ( cancel_booking )
    {
      std::cout << "Cancelling booking process and returning to the main menu.\n";
    }

}

std::string AirlineReservationSystem::GetBookingDestination()
{
  std::string destination = "";
  bool valid = false;

  while ( !valid )
  {
    // Read in the destination from the user
    std::cout << "\nPlease enter a destination.\n> ";
    std::cin.sync();
    std::cin >> destination;

	CheckReturningToMainMenu(REGULAR_USER_MENU, destination);

    // Validate the user input
    if ( AirlineRes::IsAlpha( destination ) )
    {
      valid = true;
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }

  return destination;
}

bool AirlineReservationSystem::IsYesNoChoiceValid( std::string user_input )
{
  bool valid =  false;

  if( user_input == "Y" ||  user_input == "N" || user_input == "n" || user_input == "y" )
  {
    valid = true;
  }

  return valid;
}

std::list<FlightRecord const*> AirlineReservationSystem::GetFlightShortList( std::string destination )
{
  auto flights = m_flightRecords.GetRecordSet();
  std::list<FlightRecord const*> flight_shortlist;

  // Search the set of flight records for matching destinations
  for ( auto it = flights->begin(); it != flights->end(); ++it )
  {
    if ( ConvertToLower(it->GetDestination()) == ConvertToLower( destination ) )
    {
      flight_shortlist.push_back( &(*it) );
    }
  }

  return flight_shortlist;
}

void AirlineReservationSystem::DisplayFlights( std::list<FlightRecord const*> const& shortlist )
{
  std::cout << "-----------------------------------------------------------------------------------\n";
  std::cout << "Flight ID\tFlight Code\tNumber of Seats\tTime\tDate\t\tDestination\n\n";
  std::cout << "-----------------------------------------------------------------------------------\n";
  for ( auto it = shortlist.begin(); it != shortlist.end(); ++it )
  {
    std::cout << (*it)->GetID() << "\t\t";
    std::cout << (*it)->GetFlightCode() << "\t\t";
    std::cout << (*it)->GetNumSeats() << "\t\t";
    std::cout << (*it)->GetFlightTimeDate().GetHHMM() << "\t";
    std::cout << (*it)->GetFlightTimeDate().GetDDMMYYYY() << "\t";
    std::cout << (*it)->GetDestination()<< "\t\n";
  }
  std::cout << "\n";
}

int AirlineReservationSystem::GetFlightIDChoice()
{
  std::string user_flight_id = "";
  int flight_id;
  bool valid = false;

  while ( !valid )
  {
    std::cout << "Please select a flight by the Flight ID.\n";
    std::cout << "> ";
    std::cin.sync();
    std::cin >> user_flight_id;

	CheckReturningToMainMenu(REGULAR_USER_MENU, user_flight_id);

    if ( AirlineRes::IsNumeric( user_flight_id ) )
    {
      // Convert the flight id into an int
      flight_id = atoi(  user_flight_id.c_str() );
      if ( IsFlightIDValid( flight_id ) )   
      {
        valid = true;
      }
    }  
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }

  return flight_id;
}

bool AirlineReservationSystem::IsFlightIDValid( int flight_id )
{
  bool valid =  false;
  auto flights = m_flightRecords.GetRecordSet();

  // Check the input in a valid flight number
  for ( auto it = flights->begin(); it != flights->end(); ++it )
  {
    if ( it->GetID() ==flight_id )
    {
      // If a matching flight if is found, set the validity of the flight id to true
      valid = true;
    }
  }

  return valid;
}

BookingRecord::BookingClass AirlineReservationSystem::SwitchBookingClass( BookingRecord::BookingClass booking_class )
{
  // Set the value of the alternative booking class
  BookingRecord::BookingClass alt_booking_class;

  if ( booking_class == BookingRecord::BookingClass_First )
  {
    alt_booking_class = BookingRecord::BookingClass_Economy;
  }
  else
  {
    alt_booking_class = BookingRecord::BookingClass_First;
  }

  return alt_booking_class;
}

bool AirlineReservationSystem::WantToBookAlternativeClass()
{
  std::string choice;
  bool valid = false;

  while ( !valid )
  {
    std::cout << "Would you like to make a booking on the alternative class? (Y/N): ";
    std::cin.sync();
    std::cin >> choice;

    CheckReturningToMainMenu(REGULAR_USER_MENU, choice);

    if ( IsYesNoChoiceValid( choice ) )
    {
      if( ConvertToLower( choice ) == "Y" )
      {
        return true;
      }
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }
  //Else by default return false
  return false;
}

bool AirlineReservationSystem::WantToBookReserve()
{
  std::string choice;
  bool valid = false;

  while ( !valid )
  {
    std::cout << "Would you like to make a reserve booking for this flight? (Y/N): ";
    std::cin.sync();
    std::cin >> choice;
		
    CheckReturningToMainMenu(REGULAR_USER_MENU, choice);

    if ( IsYesNoChoiceValid( choice ) )
    {
      valid = true;
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }
  return( ConvertToLower( choice ) == "Y" );
}

bool AirlineReservationSystem::IsSpace( int flight_id, BookingRecord::BookingClass booking_class )
{
  int space_remaining = 0;
  int seats = 0;
  auto bookings = m_bookingRecords.GetRecordSet();
  auto flights = m_flightRecords.GetRecordSet();

  // Match the Flight ID and get the number of seats on the flight
  for ( auto it = flights->begin(); it != flights->end(); ++it )
  {
    if ( it->GetID() == flight_id )
    {
      seats = it->GetNumSeats();
    }
  }

  if ( booking_class == BookingRecord::BookingClass_First )
  {
    // If the booking class is set to First Class
    space_remaining = seats / 10;
  }
  else if ( booking_class == BookingRecord::BookingClass_Economy )
  {
    // If the booking class is set to Economy
    space_remaining = seats - (seats / 10);
  }

  for ( auto it = bookings->begin(); it != bookings->end(); ++it )
  {
    if ( it->GetFlightID() == flight_id )
    {
      // If there is a booking, reduce the number of seats avaliable
      --space_remaining;
    }
  }

  return space_remaining > 0;
}

bool AirlineReservationSystem::AlreadyRegistered()
{
  std::string choice;

  while ( true )
  {
    std::cout << "Is the customer already registered on the system (Y/N)?\n> ";
    std::cin.sync();
    std::cin >> choice;

    CheckReturningToMainMenu(REGULAR_USER_MENU, choice);

    if ( IsYesNoChoiceValid( choice ) )
    {
      if( ConvertToLower( choice ) == "y" )
      {
        return true;
      }
      else
        return false;
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }
  //Else by default return false
  //return false;
}

int AirlineReservationSystem::GetCustomerIDChoice()
{
  std::string user_customer_id = "";
  int customer_id = 0;
  bool valid = false;

  while ( !valid )
  {
    std::cout << "Please select a customer by the Customer ID.\n";
    std::cout << "> ";
    std::cin.sync();
    std::cin >> user_customer_id;

	CheckReturningToMainMenu(REGULAR_USER_MENU, user_customer_id);

    if( AirlineRes::IsNumeric( user_customer_id ) )
    {
      // Convert the string into an integer
      customer_id = atoi( user_customer_id.c_str() );
      if ( IsCustomerIDValid( customer_id ) )   
      {
        valid = true;
      }
      else
      {
        std::cout << "Invalid Input.\n";
      }
    }
  }

  return customer_id;
}

bool AirlineReservationSystem::IsCustomerIDValid( int customer_id )
{
  bool valid =  false;
  auto customers = m_customerRecords.GetRecordSet();

  // Check the input in a valid flight number
  for ( auto it = customers->begin(); it != customers->end(); ++it )
  {
    if ( it->GetID() == customer_id )
    {
      // If a matching flight if is found, set the validity of the flight id to true
      valid = true;
    }
  }

  return valid;
}

std::string AirlineReservationSystem::GetCustomerSurname()
{
  std::string surname = "";
  bool valid = false;

  while ( !valid )
  {
    // Read in the destination from the user
    std::cout << "\nPlease enter a customer surname: ";
    std::cin.sync();
    std::cin >> surname;

    // Validate the user input
    if ( AirlineRes::IsAlpha( surname ) )
    {
      valid = true;
    }
    else
    {
      std::cout << "Invalid Input.\n";
    }
  }

  return surname;
}

std::list<CustomerRecord const*> AirlineReservationSystem::GetCustomerList( std::string surname )
{
  auto customers = m_customerRecords.GetRecordSet();
  std::list<CustomerRecord const*> customer_shortlist;

  // Search the set of flight records for matching destinations
  for ( auto it = customers->begin(); it != customers->end(); ++it )
  {
    if ( ConvertToLower(it->GetLastName()) == ConvertToLower( surname ) )
    {
      customer_shortlist.push_back( &(*it) );
    }
  }

  return customer_shortlist;
}

void AirlineReservationSystem::DisplayCustomers( std::list<CustomerRecord const*> const& shortlist )
{
  std::cout << "-----------------------------------------------------------------------------------\n";
  std::cout << "Customer ID\tPassport No.\tFirst Name\tLast Name\tD.O.B\t\tEmail\t\tPhonenumber\n\n";
  std::cout << "-----------------------------------------------------------------------------------\n";
  for ( auto it = shortlist.begin(); it != shortlist.end(); ++it )
  {
    std::cout << (*it)->GetID() << "\t\t";
    std::cout << (*it)->GetPassportNo() << "\t\t";
    std::cout  << (*it)->GetFirstName() << "\t\t";
    std::cout << (*it)->GetLastName() << "\t";
    std::cout << (*it)->GetDateOfBirth().GetDDMMYYYY() << "\t";
    std::cout << (*it)->GetEmail() << "\t";
    std::cout << (*it)->GetPhoneNo() << "\t\n";
  }
  std::cout << "\n";
}
//-------------------------------------------------------------------------------
//                             End of Reservation Functions
//===============================================================================


//-------------------------------------------------------------------------------
//                              Start of Regular User Cancellation functions.
//===============================================================================
void AirlineReservationSystem::RegularUserCancellationMenu()
{
	int intBookingId, intFlightID, intBookingClassID, intCustomerID,intBookingCustomerID, intBookingflightID, intoption;
	std::string strInput, strBookingID, strFlightCode, strDestination, strFlightDate, strFirstName,strLastName, strOption;

	intoption = 0;			//the option that user selects


	bool valid = false;

	while ( !valid )
	{
		std::cout << "\nPlease select if you want to Cancel by Booking Reference Number or by Passenger Name and Flight Number\n";
		std::cout << "1. By Booking reference Number\n2. By  Passenger Name and Flight Number" << std::endl;
		std::cout << "> ";
		std::cin.sync();
		std::cin >> strOption;

		CheckReturningToMainMenu(REGULAR_USER_MENU, strOption);

		if ( AirlineRes::IsNumeric( strOption ) )
		{
			// Convert the flight id into an int
			intoption = atoi(  strOption.c_str() );
			if ( IsFlightIDValid( intoption ) && (intoption==1 || intoption==2))   
			{
				valid = true;
			}
		} else {
			std::cout << "Invalid Input.\n";
		}
	}


	if(intoption == 2)
	{
		std::cout << "\nPlease enter the  Passenger First Name\n";
		std::cout << "> ";
		std::cin.sync();
		std::cin >> strFirstName;

		std::cout << "\nPlease enter the  Passenger Last Name\n";
		std::cout << "> ";
		std::cin.sync();
		std::cin >> strLastName;

		auto customerRS = m_customerRecords.GetRecordSet();
		intBookingCustomerID = -1;											//false if there is there is no customer with that name
		for ( auto it = customerRS->begin(); it != customerRS->end(); ++it )
		{
			if ( ( ConvertToLower(it->GetLastName()) == ConvertToLower(strLastName) ) 
				&& ( ConvertToLower(it->GetFirstName()) == ConvertToLower(strFirstName) ) )
			{
				intBookingCustomerID = it->GetID();			//customer found -> make boolean variable true
				break;
			}
		}

		if (intBookingCustomerID == -1)														//if the customer can not been found
		{
			std::cout << "\nNo customer was found with that name." << std::endl;		//print a "no found" message
			return;//ask the user if she wants to make a new customer enquiry
		}

		std::cout << "\nPlease enter the Flight Number:" << std::endl;	
		std::cout << "> ";
		std::string flightCode = "12345";
		std::cin.sync();
		std::cin >> flightCode;


		//check the flight code lenght. If it is not 5 display a non valid message
		if (flightCode.length() !=5 )
		{
			std::cout << "The flight code you entered is not valid. The flight code is a 5 digit code." << std::endl;
			return;
		}


		//check if the first two characters are alphabetic
		if ( (isalpha(flightCode[0]) == 0 ) || (isalpha(flightCode[1]) == 0) )
		{
			std::cout << "The flight code you entered is not valid. The first two digits must be alphabetic. ";

			if ( (isdigit(flightCode[2]) == 0 ) || (isdigit(flightCode[3]) == 0) || (isdigit(flightCode[4]) == 0))
			{
				std::cout << "The last three digits must be numeric";
			}

			std::cout << std::endl;
			return;
		}

		//check if the last three characters are numeric
		if ( (isdigit(flightCode[2]) == 0 ) || (isdigit(flightCode[3]) == 0) || (isdigit(flightCode[4]) == 0))
		{
			std::cout << "The flight code you entered is not valid. The last three digits must be numeric." << std::endl;
			return;
		}


		//check if the flight code exists
		intBookingflightID = -1;
		for ( auto it = m_flightRecords.GetRecordSet()->begin(); it != m_flightRecords.GetRecordSet()->end(); ++it )
		{
			if ( it->GetFlightCode().compare(flightCode) == 0 )
			{
				intBookingflightID = it->GetID();
				break;
			}
		}

		if ( intBookingflightID == -1)
		{
			std::cout << "There is no flight with such a flight code." << std::endl;
			return;
		}

		auto LstBookingRS = m_bookingRecords.GetRecordSet();
		bool blnBookingsFound=false;
		bool blnHideHeader=false;
		for ( auto it = LstBookingRS->begin(); it != LstBookingRS->end(); ++it )
		{
			if ( ( it->GetCustomerID() == intBookingCustomerID && it->GetFlightID() == intBookingflightID )  )						//when the system finds a booking for the customer ID
			{
				blnBookingsFound = true;
				if(!blnHideHeader)
				{
					blnHideHeader=true;
					std::cout << "\nBelow are the Bookings:\n";
					std::cout << "-----------------------------------------------------------------------------------------------------------------------------\n";
					std::cout << "\tBooking Ref\tFlight ID\tFlight Code\tCustomer ID\tCustomer Name\tBooking Class\n\n";
					std::cout << "------------------------------------------------------------------------------------------------------------------------------\n\t";
				}
				std::cout  << it->GetID() << "\t\t";
				std::cout  << intBookingflightID << "\t\t";
				std::cout  << flightCode  << "\t\t";
				std::cout  << intBookingCustomerID << "\t\t";
				std::cout <<  strFirstName << " " << strLastName << "\t";
				std::cout << GetBookingClassString((int)it->GetBookingClass()) << "\t\n\t";


			}
		}
		if (!blnBookingsFound)
		{
			std::cout << "\nBooking for cancelltion are not found.\n";
			return;
		}
	}

	bool blnValidBooking =  false;
	while(!blnValidBooking)
	{
		std::cout << "\nEnter the Booking Reference Number to be  Cancelled \n> ";
		std::cin.sync();
		std::cin >> strBookingID;

		CheckReturningToMainMenu(REGULAR_USER_MENU, strBookingID);

		while(IsAlpha(strBookingID))
		{
			std::cout << "\nPlease enter a proper Booking Reference Number to be Cancelled\n> ";
			std::cin.sync();
			std::cin >> strBookingID;

			CheckReturningToMainMenu(REGULAR_USER_MENU, strBookingID);

			/*
			if(strBookingID == "Q" || strBookingID == "q")
			{
			return ;
			}
			*/
		}


		intBookingId = atoi( strBookingID.c_str() );
		std::cout << "\nSearch Booking for Cancellation....\n";
		auto BookingRS = m_bookingRecords.GetRecordSet();

		auto it = std::find_if(
			BookingRS->begin(), BookingRS->end(),
			[&](BookingRecord const& _a){ return _a.GetID() == intBookingId; }
		);


		if (BookingRS->end() != it)
		{
			BookingRecord objRecord = (BookingRecord)*it;
			intCustomerID=objRecord.GetCustomerID();
			intFlightID = objRecord.GetFlightID();
			intBookingClassID = (int) objRecord.GetBookingClass();
			blnValidBooking = true;

			std::string customerFirstName = "";
			std::string customerLastName = "";
			std::string customerPassport = "";

			for ( auto it = m_customerRecords.GetRecordSet()->begin(); it != m_customerRecords.GetRecordSet()->end(); ++it )
			{
				if (it->GetID() ==  intCustomerID)
				{
					customerFirstName = it->GetFirstName();		
					customerLastName = it->GetLastName();		
					customerPassport = it->GetPassportNo();		
					break;
				}
			}

			TimeDate CurrentTimeDate;
			TimeDate FlightTimeDate;
			CurrentTimeDate.SetToCurrentTime();

			auto rsFlights =m_flightRecords.GetRecordSet();

			for ( auto itflights =  rsFlights->begin(); itflights != rsFlights->end(); ++itflights )
			{
				if ( itflights->GetID() ==intFlightID )
				{
					strDestination=itflights->GetDestination();
					strFlightCode=itflights->GetFlightCode();
					strFlightDate =itflights->GetFlightTimeDate().GetDDMMYYYY() ;
					FlightTimeDate = itflights->GetFlightTimeDate();
					break;
				}
			}

			//date today;
			if ( CurrentTimeDate.GetYear() == FlightTimeDate.GetYear() 
				&& CurrentTimeDate.GetMonth() == FlightTimeDate.GetMonth()
				&& CurrentTimeDate.GetDay() == FlightTimeDate.GetDay())
			{
				std::cout << "Cannot cancel the booking." << std::endl;
				return;
			}

			if ( CurrentTimeDate.GetYear() > FlightTimeDate.GetYear() 
				||  (CurrentTimeDate.GetYear() == FlightTimeDate.GetYear() && CurrentTimeDate.GetMonth() > FlightTimeDate.GetMonth())
				|| (CurrentTimeDate.GetYear() == FlightTimeDate.GetYear() && CurrentTimeDate.GetMonth() == FlightTimeDate.GetMonth() 
				&& CurrentTimeDate.GetDay() > FlightTimeDate.GetDay()))
			{
				std::cout << "Cannot cancel the booking.Travel date is already past" << std::endl;
				return;
			}


			std::cout << "\nSearh results: Booking Found with Booking  Reference Number " << objRecord.GetID() << "\n";

			std::cout << "\nBelow are the Booking Details:\n";
			std::cout << "-----------------------------------------------------------------------------------------------------------------------------\n";
			std::cout << "\tFlight ID\tFlight Code\tDestination\tTravel Date\tCustomer ID\tCustomer Name\tBooking Class\n\n";
			std::cout << "------------------------------------------------------------------------------------------------------------------------------\n\t";
			std::cout  << intFlightID << "\t\t";
			std::cout << strFlightCode << "\t\t";
			std::cout << strDestination << "\t\t";
			std::cout << strFlightDate << "\t";
			std::cout  << intCustomerID << "\t\t";
			std::cout <<  customerFirstName << " " << customerLastName << "\t";
			std::cout << GetBookingClassString(intBookingClassID) << "\t\n";


			if( objRecord.GetBookingClass() != BookingRecord::BookingStatus_Cancelled)
			{
				std::cout << "\nDo you want to Cancel the Booking with Booking Reference Number : " << objRecord.GetID();
				std::cout << "\n\nPress key 'Y/y' to Cancel, any other key to skip:";
				std::cin.sync();
				std::cin >> strInput;

				CheckReturningToMainMenu( REGULAR_USER_MENU, strInput );

				if (strInput == "y" || strInput == "Y"){

					objRecord.SetBookingStatus(BookingRecord::BookingStatus_Cancelled); 
					m_bookingRecords.EditRecord(objRecord);

					std::cout << "\nThe Booking is Cancelled.\n";

					auto WaitingBookingRS = m_bookingRecords.GetRecordSet();
					auto itWaiting = std::find_if(
						WaitingBookingRS->begin(), WaitingBookingRS->end(),
						[&](BookingRecord const& _a){ return _a.GetFlightID() == intFlightID 
						&& (int)_a.GetBookingClass() == intBookingClassID && _a.GetBookingStatus() == BookingRecord::BookingStatus_Reserved; }
					);

					if (WaitingBookingRS->end() != itWaiting)
					{
						BookingRecord objWaitingRecord = (BookingRecord)*itWaiting;
						objWaitingRecord.SetBookingStatus(BookingRecord::BookingStatus_Confirmed); 
						m_bookingRecords.EditRecord(objWaitingRecord);

						customerFirstName = "";
						customerLastName = "";
						customerPassport = "";

						for ( auto it = m_customerRecords.GetRecordSet()->begin(); it != m_customerRecords.GetRecordSet()->end(); ++it )
						{
							if (it->GetID() ==  objWaitingRecord.GetCustomerID())
							{
								customerFirstName = it->GetFirstName();		
								customerLastName = it->GetLastName();		
								customerPassport = it->GetPassportNo();		
								break;
							}
						}

						std::cout << "\nBooking Moved from waiting list to confirmed.\n";

						std::cout << "\nBelow are the Booking Details:\n";
						std::cout << "-----------------------------------------------------------------------------------------------------------------------------\n";
						std::cout << "\tFlight ID\tFlight Code\tDestination\tTravel Date\tCustomer ID\tCustomer Name\tBooking Class\n\n";
						std::cout << "------------------------------------------------------------------------------------------------------------------------------\n\t";
						std::cout  << intFlightID << "\t\t";
						std::cout << strFlightCode << "\t\t";
						std::cout << strDestination << "\t\t";
						std::cout << strFlightDate << "\t";
						std::cout  << objWaitingRecord.GetCustomerID() << "\t\t";
						std::cout <<  customerFirstName << " " << customerLastName << "\t";
						std::cout << GetBookingClassString(intBookingClassID) << "\t\n";
					}
				}
				else
				{
					return ;
				}
			}
			else
			{
				std::cout << "\nBooking is already cancelled with Booking Reference Number \n" << intBookingId;
			}
		}
		else
		{
			std::cout << "\nBooking for cancellation is not found with Booking Reference Number \n" << intBookingId;
			blnValidBooking = false;
		}
	}
}
//-------------------------------------------------------------------------------
//                              End of Regular User Cancellation functions
//===============================================================================
} // namespace AirlineRes
